package com.iflytek.jzcpx.procuracy.cont.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.iflytek.jzcpx.procuracy.cont.common.config.EDSConfig;
import com.iflytek.jzcpx.procuracy.cont.common.constants.Constants;
import com.iflytek.jzcpx.procuracy.cont.common.util.OcrResourcesUtil;
import com.iflytek.jzcpx.procuracy.cont.common.util.UUIDUtil;
import com.iflytek.jzcpx.procuracy.cont.model.ACDto;
import com.iflytek.jzcpx.procuracy.cont.model.ArchiveCatalogueResultDto;
import com.iflytek.jzcpx.procuracy.cont.model.Catalog;
import com.iflytek.jzcpx.procuracy.cont.model.CatalogInfoDto;
import com.iflytek.jzcpx.procuracy.cont.model.Cell;
import com.iflytek.jzcpx.procuracy.cont.model.CellData;
import com.iflytek.jzcpx.procuracy.cont.model.ContCatalogResult1;
import com.iflytek.jzcpx.procuracy.cont.model.JZML;
import com.iflytek.jzcpx.procuracy.cont.model.JZMLWJ;
import com.iflytek.jzcpx.procuracy.cont.model.OcrResult;
import com.iflytek.jzcpx.procuracy.cont.model.Page;
import com.iflytek.jzcpx.procuracy.cont.model.Table;
import com.iflytek.jzcpx.procuracy.cont.model.TaskResult;
import com.iflytek.jzcpx.procuracy.cont.service.ContService;
import com.iflytek.jzcpx.procuracy.cont.service.ElectronicArchiveService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
import java.io.File;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;

@Service
public class ElectronicArchiveServiceImpl implements ElectronicArchiveService {

	@Resource(name = "dzjzOcrContExecutor")
	private ThreadPoolTaskExecutor DZJZ_OCR_CONT_THREAD_POOL;

	private final static Logger logger = LoggerFactory.getLogger(ElectronicArchiveServiceImpl.class);

	@Autowired
	private IflytekOcrService iflytekOcrService;
	
	@Autowired
	private ContService contService;

	@Resource
	private RestTemplate restTemplate;

	@Autowired
	private EDSConfig edsConfig;

	private final static String MATCH_REGEX = ".*(目录).*";

	private final static String NOT_RECOGNIZE_FILE = "未识别材料";

	// @Value("${ali.ak}")
	// private String ak;

	// @Value("${ali.sk}")
	// private String sk;

	// @Value("${ali.requestURL}")
	// private String requestURL;

	// @Value("${ali.dzjzwj}")
	// private String dzjzwj;

	// @Value("${ali.dir}")
	// private String dir;

	@Override
	public ArchiveCatalogueResultDto ocrAndContFile(List<JZML> mlList, List<JZMLWJ> wjList, String BSBH)
			throws Exception {
		String dir = "";
		ArchiveCatalogueResultDto dto = new ArchiveCatalogueResultDto();

		if (CollectionUtils.isNotEmpty(wjList)) {
			final CountDownLatch cdl = new CountDownLatch(wjList.size());
			wjList.forEach(vo -> {
				try {
					if (StringUtils.isNotBlank(vo.getWJXH())) {
						DZJZ_OCR_CONT_THREAD_POOL.execute(() -> {
							String result = "{}";
							try {
								// File file = new File(dir + vo.getWJLJ().replaceAll("\\\\", "/"), vo.getWJMC()
								// + ".jpg");
								// result = iflytekOcrService.getOcrByFile(file, vo.getWJXH());

								// 不再从共享磁盘读取文件，换用接口的方式获取文件.
								// 如果识别结果在数据库里已经存储了，则从存储路径里获取
								if (vo.getFdfsEngineResultPath() != null) {

								} else {
									// 从接口里获取文件，进行ocr识别，并將识别结果存储下来，不存也不影响业务流程
									byte[] dataBytes=contService.getFileBytesBySWX(BSBH, vo.getWJXH());
									
									iflytekOcrService.getOcrByFile(null, "1");
								}

							} catch (Exception e) {
								e.printStackTrace();
								logger.error("获取文件,调用OCR失败", e);
							}
							// 图片识别，处理完
							if (StringUtils.isBlank(result)) {
								logger.error("wjxh:{}图像识别结果为空！！！！！！！", vo.getWJXH());
							}
							vo.setOcrRes(result);
							cdl.countDown();
						});
					} else {
						logger.info(String.format("标识编码:%s,对应的文件编号为空%s", BSBH, JSONObject.toJSONString(vo)));
					}
				} catch (Exception e) {
					logger.error(String.format("标识编码:%s,调用OCR服务失败!", BSBH), e);
				}
			});
			cdl.await();
		}
		Map<String, List<JZMLWJ>> map = wjList.stream().collect(Collectors.groupingBy(JZMLWJ::getMLBH));
		// 分卷(证据卷、文书卷)调用CONT服务,不同卷归目不一样
		for (Map.Entry<String, List<JZMLWJ>> entry : map.entrySet()) {
			List<JZMLWJ> value = entry.getValue();
			JZML jzml = null;
			List<JZML> jzmlList = mlList.stream().filter(ml -> ml.getMLBH().equals(entry.getKey()))
					.collect(Collectors.toList());
			if (CollectionUtils.isNotEmpty(jzmlList)) {
				jzml = jzmlList.get(0);
			}
			List<Catalog> catalog = catalogEngines(BSBH, value).getCatalogInfo().getCatalog();
			List<CellData> cellList = getCatalogCell(catalog, value);
			catalogByCellAndEngine(catalog, cellList, jzml, value, dto);
		}
		return dto;
	}

	/**
	 * 根据卷内目录文件和编目引擎结果编目
	 */
	private void catalogByCellAndEngine(List<Catalog> catalogList, List<CellData> cellList, JZML jzml,
			List<JZMLWJ> fileList, ArchiveCatalogueResultDto dto) {
		List<JZML> jzmlList = dto.getJZML();
		if (CollectionUtils.isEmpty(jzmlList)) {
			jzmlList = new ArrayList<>();
		}
		List<JZMLWJ> jzmlwj = dto.getJZMLWJ();
		if (CollectionUtils.isEmpty(jzmlwj)) {
			jzmlwj = new ArrayList<>();
		}
		String jzbh = "";
		if (CollectionUtils.isEmpty(fileList)) {
			jzbh = fileList.get(0).getJZBH();
		}
		String mlbhRoot = "";
		if (jzml != null && StringUtils.isNotBlank(jzml.getMLBH())) {
			mlbhRoot = jzml.getMLBH();
			jzmlList.add(jzml);
		}
		List<JZML> mlList = new ArrayList<>();
		int num = 1;
		if (CollectionUtils.isEmpty(cellList)) {
			logger.info(String.format("获取到的卷内目录文件表格信息为空!返回所有证据材料的CONT编目结果!"));
			mlList = handlerCellAndCatalog(catalogList, fileList, mlbhRoot, jzbh, num, 0, fileList.size());
		} else {
			logger.info(String.format("获取到的卷内目录文件表格信息:%s", JSONObject.toJSONString(cellList)));
			for (int i = 0; i < cellList.size(); i++) {
				CellData cellData = cellList.get(i);
				List<JZML> mlListFirst = new ArrayList<>();
				if (i == 0) {
					if (cellData.getStartNum() > 1) {
						mlListFirst = handlerCellAndCatalog(catalogList, fileList, mlbhRoot, jzbh, num, 0,
								cellData.getStartNum());
					}
				} else if (i == cellList.size() - 1) {
					if (fileList.size() > cellData.getEndNum() && cellData.getEndNum() != 0) {
						if (cellData.getEndNum() > fileList.size()) {
							return;
						}
						mlListFirst = handlerCellAndCatalog(catalogList, fileList, mlbhRoot, jzbh, num,
								cellData.getEndNum() + 1, fileList.size());
					}
				} else {
					if (cellData.getStartNum() > cellList.get(i - 1).getEndNum() + 1) {
						if (cellData.getStartNum() > fileList.size()) {
							return;
						}
						mlListFirst = handlerCellAndCatalog(catalogList, fileList, mlbhRoot, jzbh, num,
								cellList.get(i - 1).getEndNum(), cellData.getStartNum() - 1);
					}
				}
				if (cellData.getStartNum() != 0 && cellData.getEndNum() != 0
						&& StringUtils.isNotBlank(cellData.getValue().toString())) {
					JZML ml = new JZML();
					ml.setFMLBH(mlbhRoot);
					ml.setMLLX(2);
					ml.setJZBH(jzbh);
					ml.setMLSXH(num++);
					ml.setMLBH(UUIDUtil.getuuid());
					ml.setMLXSMC(cellData.getValue().toString());
					ml.setMLXX(cellData.getValue().toString());
					mlList.add(ml);
					if (cellData.getEndNum() > fileList.size()) {
						cellData.setEndNum(fileList.size());
					}
					List<JZMLWJ> wjSub = fileList.subList(cellData.getStartNum() - 1, cellData.getEndNum());
					String mlbh = "";
					if (!CollectionUtils.isEmpty(wjSub)) {
						mlbh = wjSub.get(0).getMLBH();
						if (StringUtils.isNotBlank(mlbh)) {
							for (int j = 0; j < mlList.size(); j++) {
								if (mlbh.equals(mlList.get(j).getMLBH()) && mlList.get(j).getMLLX() != 1) {
									mlList.remove(j);
								}
							}
						}
					}
					wjSub.forEach(wj -> {
						wj.setMLBH(ml.getMLBH());
					});
				} else if (cellData.getEndNum() != 0 && cellData.getStartNum() == 0 && i == 0) {
					int start = findEffectiveStartNum(cellList, i);
					mlListFirst = handlerCellAndCatalog(catalogList, fileList, mlbhRoot, jzbh, num, start,
							cellData.getEndNum());
				} else if (cellData.getStartNum() != 0 && cellData.getEndNum() == 0) {
					int end = findEffectiveEndNum(cellList, i);
					if (end != -1) {
						mlListFirst = handlerCellAndCatalog(catalogList, fileList, mlbhRoot, jzbh, num,
								cellData.getStartNum() - 1, end - 1);
					} else {
						mlListFirst = handlerCellAndCatalog(catalogList, fileList, mlbhRoot, jzbh, num,
								cellData.getStartNum() - 1, fileList.size());
					}
				}
				mlList.addAll(mlListFirst);
			}
		}
		jzmlwj.addAll(fileList);
		dto.setJZMLWJ(jzmlwj);
		jzmlList.addAll(mlList);
		dto.setJZML(jzmlList);
		fileList.forEach(wj -> {
			wj.setOcrRes(null);
			wj.setFile(null);
		});
	}

	private int findEffectiveEndNum(List<CellData> cellList, int end) {
		for (int i = end + 1; i < cellList.size(); i++) {
			if (cellList.get(i).getStartNum() != 0 && cellList.get(i).getEndNum() != 0) {
				return cellList.get(i).getStartNum();
			}
		}
		return -1;
	}

	private int findEffectiveStartNum(List<CellData> cellList, int start) {
		for (int i = 0; i < start; i++) {
			if (cellList.get(i).getStartNum() != 0 && cellList.get(i).getEndNum() != 0) {
				return cellList.get(i).getEndNum();
			}
		}
		return 0;
	}

	private List<JZML> handlerCellAndCatalog(List<Catalog> catalogList, List<JZMLWJ> fileList, String mlbhRoot,
			String jzbh, int num, int startNum, int endNum) {
		List<JZML> list = new ArrayList<>();
		for (int i = startNum; i < endNum; i++) {
			Catalog catalog = catalogList.get(i);
			JZML ml = new JZML();
			ml.setFMLBH(mlbhRoot);
			ml.setMLLX(2);
			ml.setJZBH(jzbh);
			ml.setMLSXH(num++);
			ml.setMLBH(UUIDUtil.getuuid());
			if (StringUtils.isNotBlank(catalog.getTitle().toString())
					&& !catalog.getTitle().toString().equals("unknown")) {
				ml.setMLXSMC(catalog.getTitle().toString());
				ml.setMLXX(catalog.getTitle().toString());
			} else {
				ml.setMLXSMC(NOT_RECOGNIZE_FILE);
				ml.setMLXX(NOT_RECOGNIZE_FILE);
			}
			fileList.get(i).setMLBH(ml.getMLBH());
			list.add(ml);
		}
		return list;
	}

	/**
	 * 获取卷宗目录的表格信息
	 */
	private List<CellData> getCatalogCell(List<Catalog> catalog, List<JZMLWJ> list) {
		List<CellData> data = new ArrayList<>();
		if (CollectionUtils.isEmpty(catalog)) {
			return null;
		}
		// 前10张材料中,获取卷宗目录文件
		int num = catalog.size() > 10 ? 10 : catalog.size();
		List<String> ocrList = new ArrayList<>();
		for (int i = 0; i < num; i++) {
			Catalog vo = catalog.get(i);
			logger.info(String.format("编目结果:%s", JSONObject.toJSONString(vo)));
			if (StringUtils.isNotBlank(vo.getTitle().toString())) {
				// 添加文件标题包含目录两字的材料
				if (vo.getTitle().toString().matches(MATCH_REGEX)) {
					if (StringUtils.isNotBlank(list.get(i).getOcrRes())) {
						ocrList.add(list.get(i).getOcrRes());
						for (int j = i + 1; j < num; j++) {
							// 卷宗目录材料可能存在多页情况
							if (StringUtils.isBlank(catalog.get(j).getTitle().toString())
									&& (catalog.get(j).getTitle().toString().equals(vo.getTitle().toString()))) {
								ocrList.add(list.get(j).getOcrRes());
							} else {
								break;
							}
						}
						break;
					}
				}
			}
		}
		if (CollectionUtils.isNotEmpty(ocrList)) {
			for (int i = 0; i < ocrList.size(); i++) {
				String ocrStr = ocrList.get(i);
				OcrResult ocrResult = OcrResourcesUtil.getOcrResult(ocrStr);
				TaskResult taskResult = null;
				if (ocrResult == null || (taskResult = ocrResult.getTaskResult()) == null) {
					return null;
				}
				for (Page page : taskResult.getPage()) {
					// 处理表格区域
					for (Table table : page.getTable()) {
						List<Cell> cellList = table.getCell();
						Map<Integer, List<Cell>> cellMap = cellList.stream()
								.collect(Collectors.groupingBy(Cell::getRow));
						for (Integer entry : cellMap.keySet()) {
							List<Cell> cells = cellMap.get(entry);
							// 第一张材料的第一行是表头信息,不处理.
							if (i == 0 && entry == 0) {
								continue;
							}
							handleCellData(cells, data, entry, list.size());
						}
					}
				}
			}
		}
		logger.info(String.format("获取到的表格信息:%s", JSONObject.toJSONString(data)));
		return data;
	}

	private void handleCellData(List<Cell> cells, List<CellData> data, Integer row, int size) {
		CellData cellData = new CellData();
		for (int i = 0; i < cells.size(); i++) {
			Cell cell = cells.get(i);
			if (cell.getCol() == 1) {
				if (CollectionUtils.isNotEmpty(cell.getTextline())
						&& CollectionUtils.isNotEmpty(cell.getTextline().get(0).getSent())
						&& StringUtils.isNotBlank(cell.getTextline().get(0).getSent().get(0).getValue())) {
					cellData.setValue(cell.getTextline().get(0).getSent().get(0).getValue());
				} else {
					logger.info(String.format("获取表格第 二 列第 %d 行单元格卷内目录文件材料名称为空!!!", row));
					return;
				}
			}
			if (cell.getCol() == 2) {
				if (CollectionUtils.isNotEmpty(cell.getTextline())
						&& CollectionUtils.isNotEmpty(cell.getTextline().get(0).getSent())
						&& StringUtils.isNotBlank(cell.getTextline().get(0).getSent().get(0).getValue())) {
					String value = cell.getTextline().get(0).getSent().get(0).getValue();
					try {
						String[] numStr = value.split("-");
						if (numStr.length == 2) {
							cellData.setEndNum(Integer.parseInt(numStr[1]));
						} else {
							cellData.setEndNum(Integer.parseInt(numStr[0]));
						}
						cellData.setStartNum(Integer.parseInt(numStr[0]));
						if (CollectionUtils.isNotEmpty(data) && data.get(data.size() - 1).getEndNum() == 0) {
							int startNum = Integer.parseInt(numStr[0]);
							logger.info(
									String.format("根据当前单元格的起始页码: %d ,自动补全上个为空单元格的结束页码: %d .", startNum, startNum - 1));
							data.get(data.size() - 1).setEndNum(startNum - 1);
						}
						if (cellData.getStartNum() > size || cellData.getEndNum() > size) {
							return;
						}
					} catch (Exception e) {
						e.printStackTrace();
						logger.error(String.format("页码转换异常!对应值:%s", value), e);
					}
					cellData.setPageNumStr(value);
				} else {
					logger.info(String.format("获取表格第 三 列第 %d 行单元格卷内目录文件页码为空!!!", row));
					if (CollectionUtils.isNotEmpty(data) && data.get(data.size() - 1).getEndNum() != 0) {
						int endNum = data.get(data.size() - 1).getEndNum();
						if (endNum < size) {
							logger.info(String.format("根据上个单元格的结束页码: %d ,自动补全当前为空单元格的起始页码: %d .", endNum, endNum + 1));
							cellData.setStartNum(endNum + 1);
						}
					}
				}
			}
		}
		data.add(cellData);
	}

	private CatalogInfoDto catalogEngines(String bsbh, List<JZMLWJ> files) {
		Map<String, Object> contParam = new HashMap<>();
		Map<String, Object> param = new HashMap<>();
		List<ACDto> acList = Collections.synchronizedList(new ArrayList(files.size()));
		for (int i = 0; i < files.size(); i++) {
			JZMLWJ jzmlwj = files.get(i);
			String id = jzmlwj.getWJXH() + "_" + bsbh + "_" + jzmlwj.getWJSXH();
			if (StringUtils.isNotBlank(jzmlwj.getOcrRes())) {
				acList.add(new ACDto(id, jzmlwj.getWJSXH(), JSON.parseObject(jzmlwj.getOcrRes(), JSONObject.class)));
			} else {
				acList.add(new ACDto(id, jzmlwj.getWJSXH(), JSON.parseObject("{}", JSONObject.class)));
			}
		}
		logger.debug("引擎图片数:{}", acList.size());
		acList.sort(new Comparator<ACDto>() {
			@Override
			public int compare(ACDto o1, ACDto o2) {
				return o1.getAcSort() >= o2.getAcSort() ? 1 : -1;
			}
		});
		contParam.put("ocr_list", acList);
		long start = System.currentTimeMillis();
		String ac_json;
		CatalogInfoDto cataloginfo;
		param.put("in_encode", "UTF8");
		param.put("mode", "overwrite");
		param.put("out_encode", "UTF8");
		contParam.put("trackId", bsbh + "");
		contParam.put("param", param);
		ac_json = JSON.toJSONString(contParam);
		if (contParam.get("ocr_list") == null || acList.isEmpty()) {
			logger.error("调用编目引擎参数为空：{},{}", acList, files.toString());
		}
		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.parseMediaType("application/json; charset=UTF-8"));
		String result = restTemplate.postForObject(Constants.HTTP + edsConfig.getContUrl(),
				new HttpEntity<>(ac_json, headers), String.class);
		JSONObject temp = JSONObject.parseObject(result);
		JSONObject tag_temp = JSONObject.parseObject((String) temp.get("tag"));
		temp.remove("tag");
		temp.put("tag", tag_temp);
		ContCatalogResult1 cont_result = JSON.parseObject(temp.toString(), ContCatalogResult1.class);
		if (0 == cont_result.getState().getOk()) {
			logger.error("调用自动编目发生异常！！！！异常信息：{}", cont_result);
			return null;
		}
		cataloginfo = cont_result.getTag();
		logger.info("dossierId:{}自动编目接口：：{}ms,图片数{}", bsbh, System.currentTimeMillis() - start, files.size());
		return cataloginfo;
	}
}